package com.kamistoat.meimeistore.gateway.filter;

import com.kamistoat.meimeistore.commoncore.utils.StringUtils;
import lombok.Data;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.OrderedGatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Collections;
import java.util.List;

/**
 * 自定义过滤器 全局缓存并传递body请求数据，解决POST流不能重复读取的问题。
 * 因为常规的流是不能重复读取的，这在一些场景例如 POST图片的情况下可能会引发问题。
 * 可以利用 gateway提供的全局缓存来解决这个问题。
 *
 * 本类中的 ServerWebExchangeUtils.cacheRequestBodyAndRequest() 理解不能
 */
@Component
public class CacheRequestFilter extends AbstractGatewayFilterFactory<CacheRequestFilter.Config> {
    /**
     * AbstractGatewayFilterFactory必须要实现的方法
     *
     * @param config 自定义过滤器的Config
     * @return
     */
    @Override
    public GatewayFilter apply(CacheRequestFilter.Config config) {
        // 实现 Gateway接口
        GatewayFilter gatewayFilter = new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                // GET 和 DELETE请求不需要缓存
                HttpMethod method = exchange.getRequest().getMethod();
                if (StringUtils.isNull(method) || method == HttpMethod.GET || method == HttpMethod.DELETE) {
                    return chain.filter(exchange);
                }
                // 否则全局缓存并传递。这里的原理完全不懂
                return ServerWebExchangeUtils.cacheRequestBodyAndRequest(
                        exchange,
                        // 第二个参数是一个 Function，貌似是在遍历全局缓存，把对应本次请求的流重复传递下去。
                        serverHttpRequest -> {
                            if (exchange.getRequest() == serverHttpRequest) {
                                return chain.filter(exchange);
                            } else {
                                return chain.filter(exchange.mutate().request(serverHttpRequest).build());
                            }
                        });
            }
        };

        // 按照指定的顺序插入自定义过滤器
        Integer order = config.getOrder();
        if (StringUtils.isNull(order)) {
            return gatewayFilter;
        } else {
            return new OrderedGatewayFilter(gatewayFilter, order);
        }
    }

    /**
     * 覆写 AbstractGatewayFilterFactory 中的name(), 用于返回自定义过滤器的名字
     *
     * @return
     */
    @Override
    public String name() {
        return "CacheRequestFilter";
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Collections.singletonList("order");
    }

    public CacheRequestFilter() {
        super(Config.class);
    }

    /**
     * CacheRequestFilter 对应的 Config
     */
    @Data
    public static class Config {
        private Integer order;
    }
}
